package yannan.voiplock4ble.service.ble;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.yongchun.library.BuildConfig;

import org.greenrobot.eventbus.EventBus;

import java.lang.reflect.Method;

import yannan.voiplock4ble.base.MyApplication;
import yannan.voiplock4ble.eventbus.ConnectFailedMsg;
import yannan.voiplock4ble.service.ble.callback.BleCallback;


/**
 * 说明：BLE操作核心类
 * 作者：mainTel
 * 时间：2016/9/5 10:52
 * 备注：
 */
public class BleCoreService {

    private static final int CONNECT_DEVICE = 1001;
    private static final int DIS_CONNECT_DEVICE = 1002;
    BluetoothManager mBluetoothManager;
    BluetoothAdapter mBluetoothAdapter;
    BluetoothGatt mBluetoothGatt;
    BleCallback mBleCallback;

    BluetoothGattCharacteristic mGattCharacteristic;  // 写入命令的特征
    BluetoothGattService mGattService;
    boolean mSending = false;

    String nowConnectDeviceAdd = "";
    private BluetoothGattCharacteristic gattCharacteristicAdv; //设置广播间隔

    /**
     * 初始化蓝牙
     *
     * @param paramContext
     * @return
     */
    public boolean initialize(Context paramContext) {
        int i = -1;
        if (!paramContext.getPackageManager().hasSystemFeature("android.hardware.bluetooth_le"))
            i = 0;
        while (i < 2) {
            enableBluetooth();
            if (this.mBluetoothManager == null)
                this.mBluetoothManager = (BluetoothManager) paramContext.getSystemService(Context.BLUETOOTH_SERVICE);
            if (this.mBluetoothManager == null) {
                Log.d("BleCoreService", "无法初始化mBluetoothManager");
                continue;
            }
            if (this.mBluetoothAdapter == null)
                this.mBluetoothAdapter = this.mBluetoothManager.getAdapter();
            if (this.mBluetoothAdapter == null) {
                Log.d("BleCoreService", "无法获取mBluetoothAdapter");
                continue;
            }
            boolean bool = this.mBluetoothAdapter.isEnabled();
            if (bool) {
                return true;
            } else {
                i++;
                continue;
            }
        }
        return false;
    }


    /**
     * 打开蓝牙
     */
    public void enableBluetooth() {
        if (this.mBluetoothAdapter != null)
            this.mBluetoothAdapter.enable();
    }

    /**
     * 检查蓝牙状态
     *
     * @return
     */
    public boolean checkBleStatus() {
        return initialize(MyApplication.getInterface());
    }

    /**
     * 连接设备
     *
     * @param device
     */
    public void connect(BluetoothDevice device) {
        if (checkBleStatus()) {
            if (nowConnectDeviceAdd.equals(device.getAddress()) && isConnect) {
                Log.d("BleCoreService", "BLE device has allready  connected");
                sendOrder(BleUtils.connectLock(MyApplication.getInterface().userBean.getUserAccount().getBytes()));
                return;
            }
            Message message = new Message();
            message.what = CONNECT_DEVICE;
            Bundle b = new Bundle();
            b.putParcelable("device", device);
            message.setData(b);
            handler.sendMessage(message);
        }
    }

    /**
     * 连接设备
     *
     * @param address
     */
    public void connect(String address) {
        if (checkBleStatus() && address != null) {
            if (address.equals(nowConnectDeviceAdd) && isConnect) {
                Log.d("BleCoreService", "BLE device has allready  connected");
                sendOrder(BleUtils.connectLock(MyApplication.getInterface().userBean.getUserAccount().getBytes()));
                return;
            }
            BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
            if (device == null) {
                Log.d("BleCoreService", "Device not found.  Unable to connect.");
                return;
            }
            connect(device);
        }
    }

    /**
     * 关闭链接
     */
    public void disconnect() {
        handler.sendEmptyMessage(DIS_CONNECT_DEVICE);
    }

    private boolean isConnect;
    BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {

//        boolean isOver = true;
//        int duoshaoBao = 0;
//        byte[] value;

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            super.onConnectionStateChange(gatt, status, newState);
            Log.e("蓝牙链接状态:", status + "");
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                //连接成功
                Log.d("BleCoreService", "连接成功");
                gatt.discoverServices();
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                //断开连接
                Log.d("BleCoreService", "连接断开");
                disconnect();
                mBleCallback.onConnectFailed(gatt.getDevice());
                EventBus.getDefault().post(new ConnectFailedMsg(false));
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            super.onServicesDiscovered(gatt, status);
            for (BluetoothGattService service :
                    gatt.getServices()) {
                Log.e("BluetoothGattService", service.getUuid().toString());
            }
            BluetoothGattService service = gatt.getService(BleUUID.UUID_HOLLO_DATA_SERVICE);
            mGattCharacteristic = service.getCharacteristic(BleUUID.UUID_HOLLO_DATA_SEND);
            setCharacteristicNotification(service, true);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicRead(gatt, characteristic, status);
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            Log.e("BleCoreService", "status" + status + "  " + "characteristic" + characteristic.getValue() + "gatt" + gatt.getDevice());
        }

        /**
         * 接收
         * @param gatt
         * @param characteristic
         */
        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            super.onCharacteristicChanged(gatt, characteristic);
            String str = gatt.getDevice().getAddress();
            byte[] value = characteristic.getValue();
            for (byte b :
                    value) {
                BleUtils.putByte(b);
            }
            byte[] response = BleUtils.getResponse();
            if (response.length != 0) {
                BleCoreService.this.mBleCallback.onDataReceived(str, response);
            }
        }


        @Override
        public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorRead(gatt, descriptor, status);
        }

        @Override
        public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
            super.onDescriptorWrite(gatt, descriptor, status);
            if (status == 0) {
//                gattCharacteristicAdv.setValue(new byte[]{(byte) 0xA0, 0x00});
//                mBluetoothGatt.writeCharacteristic(gattCharacteristicAdv);
                mBleCallback.onConnected(gatt.getDevice());
                isConnect = true;
            }
        }

        @Override
        public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
            super.onReliableWriteCompleted(gatt, status);
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            super.onReadRemoteRssi(gatt, rssi, status);
        }

        @Override
        public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
            super.onMtuChanged(gatt, mtu, status);
        }
    };

    /**
     * 设置通知使能
     *
     * @param service
     * @param enabled
     */
    public void setCharacteristicNotification(BluetoothGattService service, boolean enabled) {
        BluetoothGattCharacteristic characteristic = service.getCharacteristic(BleUUID.UUID_HOLLO_DATA_RECEIVE);
        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);
        //需要为指定特征的特定的描述符设置启用才行
        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(BleUUID.UUID_CLIENT_CHARACTERISTIC_CONFIG);
        if (descriptor != null) {
            System.out.println("write descriptor");
            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
            mBluetoothGatt.writeDescriptor(descriptor);
//            descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
//            mBluetoothGatt.writeDescriptor(descriptor);
            gattCharacteristicAdv = service.getCharacteristic(BleUUID.UUID_HOLLO_DATA_ADV);

        }
    }

    public void setBleCallback(BleCallback paramBleCallback) {
        this.mBleCallback = paramBleCallback;
    }

    /**
     * 发送命令
     *
     * @param paramArrayOfByte
     */
    public void sendOrder(final byte[] paramArrayOfByte) {
        new Thread(new Runnable() {
            public void run() {
                int i = BleCoreService.this.sendRunnable(paramArrayOfByte);
                if (BleCoreService.this.mBleCallback != null)
                    BleCoreService.this.mBleCallback.onSendFinish(i);
            }
        }).start();
    }

    Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case CONNECT_DEVICE:
                    if (null != mBluetoothGatt) {
                        mBluetoothGatt.disconnect();
                        mBluetoothGatt.close();
                    }
                    BluetoothDevice device = msg.getData().getParcelable("device");
                    mBluetoothGatt = device.connectGatt(MyApplication.getInterface(), false, bluetoothGattCallback);
                    nowConnectDeviceAdd = device.getAddress();
                    break;
                case DIS_CONNECT_DEVICE:
                    try {
                        if (mBluetoothGatt != null) {
                            mBluetoothGatt.disconnect();
                            mBluetoothGatt.close();
                            refreshDeviceCache();
                            nowConnectDeviceAdd = "";
                            clearConnect();
                            isConnect = false;
                            EventBus.getDefault().post(new ConnectFailedMsg(false));
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    break;
            }
        }
    };

    private int sendRunnable(byte[] value) {
        if (mBluetoothGatt != null && mGattCharacteristic != null) {
            System.out.println("--------------------------");
            for (byte b :
                    value) {
                System.out.print(String.format("%02X ", b));
            }
            System.out.println();
            System.out.println("--------------------------");
            if (value.length > 20) {
                int m = value.length % 20;
                for (int i = 0; i < value.length / 20; i++) {
                    byte[] a = new byte[20];
                    for (int j = 0; j < 20; j++) {
                        a[j] = value[20 * i + j];
                    }
                    try {
                        Thread.sleep(15);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    mGattCharacteristic.setValue(a);
                    //不用等返回写入成功 连续写入
                    mGattCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
                    mBluetoothGatt.writeCharacteristic(mGattCharacteristic);
                }
                if (0 != m) { //还没有传完
                    try {
                        Thread.sleep(15);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    byte[] a = new byte[m];
                    System.arraycopy(value, value.length - m, a, 0, m);
                    mGattCharacteristic.setValue(a);
                    mGattCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
                    mBluetoothGatt.writeCharacteristic(mGattCharacteristic);
                }
                return 0;
            } else {
                mGattCharacteristic.setValue(value);
                mGattCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
                mBluetoothGatt.writeCharacteristic(mGattCharacteristic);
                return 0;
            }
        }
        //发送失败
        return -1;
    }

    /**
     * 清除链接
     */
    public void clearConnect() {
        MyApplication.getInterface().mConnectLock = null;
    }


    public boolean refreshDeviceCache() {
        try {
            Method e = BluetoothGatt.class.getMethod("refresh", new Class[0]);
            if (e != null) {
                boolean success = ((Boolean) e.invoke(mBluetoothGatt, new Object[0])).booleanValue();
                if (yannan.voiplock4ble.BuildConfig.DEBUG)
                    Log.e("BleCoreService", "Refreshing result: " + success);
                return success;
            }
        } catch (Exception var3) {
            if (yannan.voiplock4ble.BuildConfig.DEBUG)
                Log.e("BleCoreService", "An exception occured while refreshing device", var3);
        }

        return false;
    }

}
